package com.bootdo.system.service.impl;

import com.bootdo.common.utils.DateUtils;
import com.bootdo.common.utils.R;
import com.bootdo.common.utils.StringUtils;
import com.bootdo.common.utils.encryptionUtil.Header;
import com.bootdo.common.utils.encryptionUtil.PCIPHER_HEADER;
import com.bootdo.common.utils.encryptionUtil.Seal;
import com.bootdo.common.utils.httpUtils.DownLoadFile;
import com.bootdo.system.dao.FileInfoDao;
import com.bootdo.system.dao.FileShareDao;
import com.bootdo.system.dao.SetDao;
import com.bootdo.system.dao.UserFileDao;
import com.bootdo.system.domain.*;
import com.bootdo.system.service.FileShareService;
import com.bootdo.system.service.UserFileService;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.bootdo.common.utils.encryptionUtil.Seal.InitEncryptKey;

@Service
@Transactional
public class FileShareServiceImpl implements FileShareService {

	@Autowired
	private UserFileService userFileService;
	
	@Autowired
	private FileShareDao fileShareDao;

	@Autowired
	private UserFileDao userFileDao;

	@Autowired
	private FileInfoDao fileInfoDao;

	@Autowired
	private SetDao setDao;

	List<UserFileDO> list1 = new ArrayList<UserFileDO>();

	@Override
	public FileShareDO get(Long id){
		return fileShareDao.get(id);
	}
	
	@Override
	public List<FileShareDO> list(Map<String, Object> map){
		return fileShareDao.list(map);
	}
	
	@Override
	public int count(Map<String, Object> map){
		return fileShareDao.count(map);
	}
	
	@Override
	public int save(FileShareDO fileShareDO){
		return fileShareDao.save(fileShareDO);
	}
	
	@Override
	public int update(FileShareDO fileShareDO){
		return fileShareDao.update(fileShareDO);
	}
	
	@Override
	public int remove(Long id){
		return fileShareDao.remove(id);
	}
	
	@Override
	public int batchRemove(Long[] ids){
		return fileShareDao.batchRemove(ids);
	}

	/**
	 * 生成文件分享链接
	 * @param fileShareDO
	 * @return
	 */
	@Override
	public R createShareLink(FileShareDO fileShareDO) {
		R r = new R();
		//获取文件详情
		UserFileDO userFileDO = userFileDao.get(fileShareDO.getFileId());
		if(userFileDO.getIsFolder() == 0) {
			//表示文件，需要判断是否是病毒文件
			//判断文件是是否是病毒文件（-1：类型检查失败，-2：存在病毒，-3：加密失败，0：上传成功）
			if(null != userFileDO.getStatus() && userFileDO.getStatus() == -2) {
				return R.error(1,"文件名为" + userFileDO.getFilename() + "的文件存在病毒，不可分享");
			}
		}
		//默认分享0次
		fileShareDO.setShareCount(0);
		fileShareDO.setAddTime(new Date());
		fileShareDO.setDelFlag("0");//有效
		fileShareDao.save(fileShareDO);
		return r;
	}

	/**
	 * 判断文件是否可以下载
	 * @param fileShareDO
	 * @return
	 */
	@Override
	public R judeDownloadFile(FileShareDO fileShareDO) {
		R r = new R();
		if(StringUtils.equals("1",fileShareDO.getFlag())) {
			//获取文件地址
			UserFileDO userFileDO = userFileDao.get(fileShareDO.getFileId());
			if(null == userFileDO) {
				return R.error("文件不存在");
			}
			//判断文件是否存在
			//获取文件保存根目录地址
			SetDO setDO = setDao.get("diskSave");
			String rootPath = setDO.getSetValue();

			if(0 == userFileDO.getIsFolder()) {
				//获取文件file_info信息
				Map<String,Object> map = new HashMap<String, Object>();
				map.put("uuid",userFileDO.getFileuuid());
				FileInfoDO fileInfoDO = fileInfoDao.getFileInfoDetail(map);

				String filePth= rootPath + File.separator + "ENCRY_" + fileInfoDO.getUuid() + fileInfoDO.getFilename() + "." + fileInfoDO.getFiletype();
				File file = new File(filePth);
				if(!file.exists()) {
					// 文件不存在
					return R.error("文件不存在");
				}
			}
			//判断文件是是否是病毒文件（-1：类型检查失败，-2：存在病毒，-3：加密失败，0：上传成功）
			if(null != userFileDO.getStatus() && userFileDO.getStatus() == -2) {
				return R.error(1,"文件名为" + userFileDO.getFilename() + "的文件存在病毒，不可下载");
			}
		}
		if(StringUtils.equals("2",fileShareDO.getFlag())) {
			//获取分享详情
			FileShareDO fileShareDO1 = fileShareDao.getByUuid(fileShareDO.getUuid());
			//获取文件地址
			UserFileDO userFileDO = userFileDao.get(fileShareDO1.getFileId());
			if(null == userFileDO) {
				return R.error("文件不存在");
			}
			//判断文件提取码
			if(!StringUtils.equals(fileShareDO.getShareCode(),fileShareDO1.getShareCode())) {
				return R.error("文件提取码不正确");
			}
			//判断文件有效期(有效期（单位天数；0代表永久有效）)
			if(0 != fileShareDO1.getSharePeriod()) {
				//计算到期时间天数差值
				long day = DateUtils.getDaySub(fileShareDO1.getAddTime());
				if(day > fileShareDO1.getSharePeriod()) {
					return R.error("文件已到期");
				}
			}
		}
		return R.ok();
	}

	/**
	 * 根据加密链接地址获取分享详情
	 * @param shareLinkMd5
	 * @return
	 */
	@Override
	public FileShareDO getDetailByshareLinkMd5(String shareLinkMd5) {
		FileShareDO fileShareDO = fileShareDao.getDetailByshareLinkMd5(shareLinkMd5);
		return fileShareDO;
	}

	/**
	 * 文件下载
	 * @param fileShareDO
	 * @return
	 */
	@Override
	public R downloadFile(FileShareDO fileShareDO, HttpServletRequest request,HttpServletResponse response) {
		list1 = new ArrayList<UserFileDO>();
		R r = new R();
		//获取文件地址
		UserFileDO userFileDO = userFileDao.get(fileShareDO.getFileId());
		try {
			//获取文件保存根目录地址
			SetDO setDO = setDao.get("diskSave");
			String rootPath = setDO.getSetValue();

			//downloadAllAttachment(userFileDO.getFilename(),path,request,response,rootPath);

			//单个文件下载，直接下载即可；文件夹下载，打包压缩下载
			if(userFileDO.getIsFolder() == 0) {
				//不是目录，直接下载
				// path是指欲下载的文件的路径。

				//获取文件file_info信息
				Map<String,Object> map = new HashMap<String, Object>();
				map.put("uuid",userFileDO.getFileuuid());
				FileInfoDO fileInfoDO = fileInfoDao.getFileInfoDetail(map);
				// 取得文件名
				String filename = userFileDO.getFilename();
				// 取得文件名后缀名
				String ext = userFileDO.getFiletype();
				String name = filename + "." + ext;

                String filePth = rootPath + File.separator + "ENCRY_" + fileInfoDO.getUuid() + fileInfoDO.getFilename() + "." + fileInfoDO.getFiletype();
                //文件下载
				DownLoadFile.downloadFile(filePth,rootPath,fileInfoDO.getFilename(),fileInfoDO.getFiletype(),name,response, null, null, null);
				/*File file = new File(path);
				// 取得文件名
				String filename = userFileDO.getFilename();
				// 取得文件名后缀名
				String ext = userFileDO.getFiletype();
				String name = filename + "." + ext;

				// 以流的形式下载文件。
				InputStream fis = new BufferedInputStream(new FileInputStream(path));
				byte[] buffer = new byte[fis.available()];
				fis.read(buffer);
				fis.close();
				// 清空response
				response.reset();
				// 设置response的Header
				response.addHeader("Content-Disposition", "attachment;filename=" + new String(name.getBytes("utf-8"),"ISO8859-1"));
				response.addHeader("Content-Length", "" + file.length());
				OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
				response.setContentType("application/octet-stream");
				toClient.write(buffer);
				toClient.flush();
				toClient.close();*/
			}else {
				//递归该文件夹下所有文件
				list1 = recursionFileFor(userFileDO.getId());
				////删除集合中某一元素值
				Iterator<UserFileDO> iterator = list1.iterator();
				while (iterator.hasNext()){
					UserFileDO next = iterator.next();
					Integer isFloader = next.getIsFolder();
					if (1 == isFloader){
						iterator.remove();
					}
				}
				List<File> filesList = new ArrayList<>();
				File[] files=new File[list1.size()];
				String path1;
				for (int j = 0; j < list1.size(); j++) {
					path1 = rootPath + File.separator + list1.get(j).getFilename() + "." + list1.get(j).getFiletype();
					File file = new File(path1);
					files[j]=file;
					filesList.add(file);
				}
				downLoadFiles(userFileDO.getFilename(),filesList,rootPath,request,response,rootPath,list1);
				//这里的文件你可以自定义是.rar还是.zip
				String filePath = rootPath + File.separator + userFileDO.getFilename() + "压缩.zip";
				File file = new File(filePath);
				if (file.exists()){
					//如果压缩包已经存在则删除
					file.delete();
				}
			}
		} catch (IOException ex) {
			ex.printStackTrace();
			return R.error("文件下载失败");
		} catch (Exception e) {
			e.printStackTrace();
			return R.error("文件下载失败");
		}
		//文件下载成功
        //文件下载数量加1
        fileShareDao.addCount(fileShareDO);
		return r;
	}

	public List<UserFileDO> recursionFileFor(Integer id) {
		UserFileDO userFileDO1 = new UserFileDO();
		userFileDO1.setId(id);
		List<UserFileDO> list = userFileService.listFileFor(userFileDO1);
		if (!CollectionUtils.isEmpty(list)) {
			list1.addAll(list);
			for (UserFileDO data : list) {
				list = recursionFileFor(data.getId());
			}
		}
		return list1;
	}


	//以下为老师打包下载全部学生的报告
	public String downloadAllAttachment(String fielName, String filePath, HttpServletRequest request, HttpServletResponse response, String rootPath) throws Exception {
		File dirFile = new File(filePath) ;
		ArrayList<String> allFilePath = Dir(dirFile);
		List<File> filesList = new ArrayList<>();

		File[] files=new File[allFilePath.size()];
		String path;
		for (int j = 0; j < allFilePath.size(); j++) {
			path=allFilePath.get(j);
			File file = new File(path);
			files[j]=file;
			filesList.add(file);
		}
		return downLoadFiles(fielName,filesList,filePath,request,response,rootPath, list1);

	}

	//获取文件夹下的所有文件的路径
	public static ArrayList<String> Dir(File dirFile) throws Exception {
		ArrayList<String> dirStrArr = new ArrayList<String>();
		if (dirFile.exists()) {
			//直接取出利用listFiles()把当前路径下的所有文件夹、文件存放到一个文件数组
			File files[] = dirFile.listFiles();
			// 获取文件的后缀名
			String fileName = dirFile.getName();
			if(fileName.contains(".")) {
				//表示是文件而不是文件夹
				dirStrArr.add(dirFile.getPath());
			}
			if(null != files && files.length > 0) {
				for (File file : files) {
					//直接不下载加密的文件即可
					if(!StringUtils.contains(file.getName(),"ENCRY_")) {
						//如果传递过来的参数dirFile是以文件分隔符，也就是/或者\结尾，则如此构造
						if (dirFile.getPath().endsWith(File.separator)) {
							dirStrArr.add(dirFile.getPath() + file.getName());
						} else {
							//否则，如果没有文件分隔符，则补上一个文件分隔符，再加上文件名，才是路径
							dirStrArr.add(dirFile.getPath() + File.separator
									+ file.getName());
						}
					}
				}
			}
		}
		return dirStrArr;
	}

	//下载文件
	public String downLoadFiles(String fielName, List<File> files, String filePath, HttpServletRequest request, HttpServletResponse response, String rootPath, List<UserFileDO> list1) throws Exception {

		OutputStream out = null;
		FileInputStream in = null;
		try {
			//这里的文件你可以自定义是.rar还是.zip
			filePath = rootPath + File.separator + fielName + "压缩.zip";
			File file = new File(filePath);
			if (!file.exists()){
				file.createNewFile();
			}else{
				//如果压缩包已经存在则删除后重新打包压缩
				file.delete();
				file.createNewFile();
			}
			response.reset();
			in = new FileInputStream(file);

			//创建文件输出流
			FileOutputStream fous = new FileOutputStream(file);
			/**打包的方法用到ZipOutputStream这样一个输出流,所以这里把输出流转换一下*/
			ZipOutputStream zipOut = new ZipOutputStream(fous);
			/**这个方法接受的就是一个所要打包文件的集合，还有一个ZipOutputStream*/
			zipFiles(files, zipOut,list1,rootPath,response);
			zipOut.close();
			fous.close();
			// 将要下载的文件内容通过输出流写到浏览器
			out = response.getOutputStream();
			// 设置一个响应头，无论是否被浏览器解析，都下载
			response.setHeader("Content-Disposition", "attachment;filename="
					+ new String(fielName.getBytes("utf-8"), "ISO-8859-1") + ".zip");
			// 设置response的Header
			response.setContentType("application/octet-stream");
			response.setCharacterEncoding("utf-8");
			int len = 0;
			byte[] buffer = new byte[1024];
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
			return filePath;

		}catch (Exception e) {
			e.printStackTrace();
			//return "文件下载出错" ;
		} finally {
			if (out != null) {
				out.close();
			}
			if (in != null) {
				in.close();
			}
		}
		return "文件下载出错";
	}

	//把接受的全部文件打成压缩包
	public void zipFiles(List files, ZipOutputStream outputStream, List<UserFileDO> list1, String rootPath, HttpServletResponse response) throws IOException {
		/*int size = files.size();
		for(int i = 0; i < size; i++) {
			File file = (File) files.get(i);
			zipFile(file, outputStream);
		}*/
		if(!CollectionUtils.isEmpty(list1)) {
			Map<String,Object> map = null;
			List<DownLoadDO> fileNameStrList = new ArrayList<DownLoadDO>();
			for(UserFileDO data1 : list1) {
				DownLoadDO downLoadDO = new DownLoadDO();
				map = new HashMap<String, Object>();
				map.put("uuid",data1.getFileuuid());
				FileInfoDO fileInfoDO = fileInfoDao.getFileInfoDetail(map);
				downLoadDO.setFileNameStr(data1.getFilename() + "." + fileInfoDO.getFiletype());
				fileNameStrList.add(downLoadDO);
			}
			//去重
			List<DownLoadDO> fileNameStrLists = fileNameStrList.stream()
					.collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(DownLoadDO::getFileNameStr))), ArrayList::new));

			for(UserFileDO data : list1) {
				map = new HashMap<String, Object>();
				map.put("uuid",data.getFileuuid());
				FileInfoDO fileInfoDO = fileInfoDao.getFileInfoDetail(map);
				String path1 = rootPath + File.separator + "ENCRY_" + fileInfoDO.getUuid() + fileInfoDO.getFilename() + "." + fileInfoDO.getFiletype();
				File file = new File(path1);
				zipFile(file, outputStream,data,fileNameStrLists,rootPath,response);
			}
		}
	}

	//将单个文件打包
	public void zipFile(File inputFile, ZipOutputStream ouputStream, UserFileDO userFileDO, List<DownLoadDO> fileNameStrList, String rootPath, HttpServletResponse response) throws IOException {
		try {
			if (inputFile.exists()) {
				if (inputFile.isFile()) {
					ZipEntry entry = null;
					FileInputStream IN = new FileInputStream(inputFile);
					BufferedInputStream bins = new BufferedInputStream(IN, 512);
					String fileNameExt = userFileDO.getFilename() + "." + userFileDO.getFiletype();
					if(!CollectionUtils.isEmpty(fileNameStrList)) {
						for(DownLoadDO data : fileNameStrList) {
							if(StringUtils.equals(fileNameExt,data.getFileNameStr())) {
								if(0 == data.getIndex()) {
									//org.apache.tools.zip.ZipEntry
									entry = new ZipEntry(fileNameExt);
								}else {
									//org.apache.tools.zip.ZipEntry
									entry = new ZipEntry(userFileDO.getFilename() + "(" + data.getIndex() + ")." + userFileDO.getFiletype());
								}
								data.setIndex(data.getIndex() + 1);
							}
						}
					}
					ouputStream.putNextEntry(entry);
					String filePath = rootPath + File.separator +  "ENCRY_" + userFileDO.getFileuuid() + fileNameExt;
					File originalFile =new File(filePath);
					//解密文件
					File targetFile = new File(rootPath + File.separator + userFileDO.getFilename() + "." + userFileDO.getFiletype());
					//文件下载
					//DownLoadFile.downloadFile(filePath,rootPath,userFileDO.getFilename(),userFileDO.getFiletype(),fileNameExt,response,ouputStream,IN,bins);
					RandomAccessFile sourceFile = null;
					Seal seal = new Seal();
					Seal.seal_ctx sc = seal.new seal_ctx();
					InitEncryptKey(seal, sc);
					PCIPHER_HEADER pHeader = new Header().BuildCipherHeader();

					//-------------下面是解密文件的测试
					String source = "";
					String destination = "";
					try {
						//加密文件路径
						source = originalFile.getPath();
						//解密文件路径
						destination = targetFile.getPath();
						sourceFile = new RandomAccessFile(source, "r");
					} catch (Exception e) {
						//文件没有找到
					}


					long nFileLen = sourceFile.length();

					//加密文件的长度至少是1024字节长度！
					if (nFileLen <= ENCFILE_HEAD_LEN) {
						sourceFile.close();
					}

					//表示两个32位的头
					byte[] MainFlag = new byte[MAX_CIPHER_MAIN_FLAG];
					byte[] FlagEncData = new byte[MAX_CIPHER_MAIN_FLAG];
					byte[] unknown = new byte[149];

					sourceFile.read(MainFlag);
					sourceFile.seek(32);
					sourceFile.read(FlagEncData);
					sourceFile.seek(64);
					sourceFile.read(unknown);

					int dwRetVal = 32;

					Seal.bytearray HEADER_FLAGENCDATA = seal.new bytearray(MAX_CIPHER_MAIN_FLAG);
					for (int i = 0; i < MAX_CIPHER_MAIN_FLAG; i++) {
						HEADER_FLAGENCDATA.a[i] = Header.gConstCipherFlagBuffer.a[i];
					}
					seal.seal_encrypt(sc, HEADER_FLAGENCDATA, dwRetVal, 0x00);

					//对两个开头进行判断
					/*for (int i = 0; i < MAX_CIPHER_MAIN_FLAG; i++) {
						if (MainFlag[i] != gConstCipherFlagBuffer.a[i]) {
							return -3;
						}

						if (FlagEncData[i] != HEADER_FLAGENCDATA.a[i]) {
							return -3;
						}
					}*/

					try {
					   /* OutputStream fos = new FileOutputStream(destination);
						BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER_SIZE);*/
						sourceFile.seek(ENCFILE_HEAD_LEN);


						long nLeftLen = nFileLen - ENCFILE_HEAD_LEN;
						long OffsetValue = ENCFILE_HEAD_LEN;
						Seal.bytearray FileBuf = seal.new bytearray(BUFFER_SIZE);
						byte[] bytes = new byte[BUFFER_SIZE];
						while (nLeftLen > 0) {
							int nRead = sourceFile.read(bytes);
							if (nRead <= 0)
								break;

							nLeftLen = nLeftLen - nRead;

							for (int i = 0; i < nRead; i++)
								FileBuf.a[i] = bytes[i];

							seal.seal_decrypt(sc, FileBuf, nRead, OffsetValue);
							for (int i = 0; i < nRead; i++)
								bytes[i] = FileBuf.a[i];

							ouputStream.write(bytes,0, nRead);

							OffsetValue += nRead;
						}

						//关闭创建的流对象
						bins.close();
						IN.close();

						sourceFile.close();
					} catch (Exception e) {
						e.printStackTrace();
					}

					// 向压缩文件中输出数据
					/*int nNumber;
					byte[] buffer = new byte[512];
					while ((nNumber = bins.read(buffer)) != -1) {
						ouputStream.write(buffer, 0, nNumber);
					}
					//关闭创建的流对象
					bins.close();
					IN.close();*/
				} else {
					try {
						File[] files = inputFile.listFiles();
						for (File file : files) {
							if(!StringUtils.contains(file.getName(),"ENCRY_")) {
								zipFile(file, ouputStream, userFileDO, fileNameStrList, rootPath, response);
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static final int BUFFER_SIZE = 0x10000;
	public static final int CIPHER_HEDER_SIZE = 1024;
	public static final int MAX_CIPHER_MAIN_FLAG = 32;
	public static final int MAX_KEY_INFO = 16;
	public static int ENCFILE_HEAD_LEN = 1024;


	/**
	 * 解密文件的操作，返回值为int类型，根据返回值的不同，接收不同的结果
	 * 1：文件正常解密
	 * -1：文件没有找到
	 * -2：加密文件至少有1024字节，源文件少于这个长度
	 * -3：源文件没有包含加密时放入的密码，即不是采用本系统进行加密
	 * -4：在写入文件时出现的其他异常
	 *
	 * @param originalFile
	 * @param targetFile
	 * @param ouputStream
	 * @param IN
	 * @param bins
	 * @return
	 * @throws Exception
	 */
	public static int DecryptFile(File originalFile, File targetFile, String name, HttpServletResponse response, ZipOutputStream ouputStream, FileInputStream IN, BufferedInputStream bins) throws Exception {
		RandomAccessFile sourceFile = null;
		Seal seal = new Seal();
		Seal.seal_ctx sc = seal.new seal_ctx();
		InitEncryptKey(seal, sc);
		PCIPHER_HEADER pHeader = new Header().BuildCipherHeader();

		//-------------下面是解密文件的测试
		String source = "";
		String destination = "";
		try {
			//加密文件路径
			source = originalFile.getPath();
			//解密文件路径
			destination = targetFile.getPath();
			sourceFile = new RandomAccessFile(source, "r");
		} catch (Exception e) {
			//文件没有找到
			return -1;
		}


		long nFileLen = sourceFile.length();

		//加密文件的长度至少是1024字节长度！
		if (nFileLen <= ENCFILE_HEAD_LEN) {
			sourceFile.close();
			return -2;
		}

		//表示两个32位的头
		byte[] MainFlag = new byte[MAX_CIPHER_MAIN_FLAG];
		byte[] FlagEncData = new byte[MAX_CIPHER_MAIN_FLAG];
		byte[] unknown = new byte[149];

		sourceFile.read(MainFlag);
		sourceFile.seek(32);
		sourceFile.read(FlagEncData);
		sourceFile.seek(64);
		sourceFile.read(unknown);

		int dwRetVal = 32;

		Seal.bytearray HEADER_FLAGENCDATA = seal.new bytearray(MAX_CIPHER_MAIN_FLAG);
		for (int i = 0; i < MAX_CIPHER_MAIN_FLAG; i++) {
			HEADER_FLAGENCDATA.a[i] = Header.gConstCipherFlagBuffer.a[i];
		}
		seal.seal_encrypt(sc, HEADER_FLAGENCDATA, dwRetVal, 0x00);


		//对两个开头进行判断
		for (int i = 0; i < MAX_CIPHER_MAIN_FLAG; i++) {
			if (MainFlag[i] != Header.gConstCipherFlagBuffer.a[i]) {
				return -3;
			}

			if (FlagEncData[i] != HEADER_FLAGENCDATA.a[i]) {
				return -3;
			}
		}


		try {
           /* OutputStream fos = new FileOutputStream(destination);
            BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER_SIZE);*/
			sourceFile.seek(ENCFILE_HEAD_LEN);


			long nLeftLen = nFileLen - ENCFILE_HEAD_LEN;
			long OffsetValue = ENCFILE_HEAD_LEN;
			Seal.bytearray FileBuf = seal.new bytearray(BUFFER_SIZE);
			byte[] bytes = new byte[BUFFER_SIZE];
			while (nLeftLen > 0) {
				int nRead = sourceFile.read(bytes);
				if (nRead <= 0)
					break;

				nLeftLen = nLeftLen - nRead;

				for (int i = 0; i < nRead; i++)
					FileBuf.a[i] = bytes[i];

				seal.seal_decrypt(sc, FileBuf, nRead, OffsetValue);
				for (int i = 0; i < nRead; i++)
					bytes[i] = FileBuf.a[i];
				if(null != ouputStream) {
					ouputStream.write(bytes);
				}

				OffsetValue += nRead;
			}
			if(null != ouputStream) {
				//关闭创建的流对象
				bins.close();
				IN.close();
			}

			sourceFile.close();
			return 1;
		} catch (Exception e) {
			e.printStackTrace();
			return -4;
		}
	}

}